_require local "../../../../basis.smi"
_require       "../../../compilerIRs/recordcalc/main/RecordCalc.ppg.smi"
_require       "../../../compilerIRs/typedlambda/main/TypedLambda.ppg.smi"
_require local "../../../data/builtin/main/BuiltinPrimitive.ppg.smi"
_require local "../../../data/builtin/main/BuiltinTypes.smi"
_require       "../../../data/symbols/main/Loc.smi"
_require       "../../../data/symbols/main/RecordLabel.smi"
_require local "../../../data/symbols/main/Symbol.smi"
_require       "../../../data/types/main/Types.ppg.smi"
_require local "../../../data/types/main/TypesBasics.smi"
_require local "../../../extensions/debug/main/Bug.smi"

_require local "../../../data/types/main/TypesBasics.smi"
_require local "../../../data/builtin/main/BuiltinTypes.smi"
_require local "../../../data/builtin/main/BuiltinPrimitive.ppg.smi"

_require "../../../data/symbols/main/Loc.smi"
_require "../../../data/symbols/main/Symbol.smi"
_require "../../../data/symbols/main/RecordLabel.smi"
_require "../../../libs/ids/main/LocalID.smi"
_require "../../../compilerIRs/typedlambda/main/TypedLambda.ppg.smi"
_require "../../../data/types/main/Types.ppg.smi"

structure EmitTypedLambda =
struct

  type vid (= VarID.id)
  val newId : unit -> vid

  datatype exp =
      Exp of TypedLambda.tlexp * Types.ty
    | Const of TypedLambda.tlconst
    | Int of TypedLambda.tlint
    | Int8 of int
    | Int16 of int
    | Int32 of int
    | Int64 of int
    | Word8 of int
    | Word16 of int
    | Word32 of int
    | Word64 of int
    | Char of int
    | ConTag of int
    | Real64 of real64
    | Real32 of real32
    | String of string
    | Unit
    | Null
    | True
    | False
    | SizeOf of Types.ty
    | IndexOf of Types.ty * RecordLabel.label
    | ExVar of TypedLambda.exVarInfo
    | Cast of exp * Types.ty
    | BitCast of exp * Types.ty
    | PrimApply of TypedLambda.primInfo * Types.ty list * Types.ty * exp list
    | If of exp * exp * exp
    | Andalso of exp list
    | Switch of exp * (TypedLambda.tlint * exp) list * exp
    | Raise of Types.exExnInfo * Types.ty
    | Fn of vid * Types.ty * exp
    | App of exp * exp
    | Let of (vid * exp) list * exp
    | Var of vid
    | TLLet of decl list * exp
    | TLVar of TypedLambda.varInfo
    | Record of RecordLabel.label list * exp list
    | Select of RecordLabel.label * exp
  and decl =
      Decl of TypedLambda.tldecl * TypedLambda.loc
    | Bind of TypedLambda.varInfo * exp

  val tupleTy : Types.ty list -> Types.ty
  val arrayTy : Types.ty -> Types.ty

  val Tuple : exp list -> exp
  val SelectN : int * exp -> exp
  val Ref_alloc : Types.ty * exp -> exp
  val Ref_deref : Types.ty * exp -> exp
  val Ref_assign : Types.ty * exp * exp -> exp
  val Array_length : Types.ty * exp -> exp
  val Array_sub_unsafe : Types.ty * exp * exp -> exp
  val Array_alloc_unsafe : Types.ty * exp -> exp
  val Array_alloc_init : Types.ty * exp list -> exp
  val Array_update_unsafe : Types.ty * exp * exp * exp -> exp
  val Array_copy_unsafe : Types.ty * exp * exp * exp * exp * exp -> exp
  val String_alloc_unsafe : exp -> exp
  val String_size : exp -> exp
  val String_sub_unsafe : exp * exp -> exp
  val String_update_unsafe : exp * exp * exp -> exp
  val String_copy_unsafe : exp * exp * exp * exp * exp -> exp
  val Vector_alloc_unsafe : Types.ty * exp -> exp
  val IdentityEqual : Types.ty * exp * exp -> exp
  val IsNull : exp -> exp
  val Int_eq : Types.ty -> exp * exp -> exp
  val Int_lt : Types.ty -> exp * exp -> exp
  val Int_lteq : Types.ty -> exp * exp -> exp
  val Int_gteq : Types.ty -> exp * exp -> exp
  val Int_quot_unsafe : Types.ty -> exp * exp -> exp
  val Int_rem_unsafe : Types.ty -> exp * exp -> exp
  val Int_add_unsafe : Types.ty -> exp * exp -> exp
  val Int_mul_unsafe : Types.ty -> exp * exp -> exp
  val Int_sub_unsafe : Types.ty -> exp * exp -> exp
  val Int_add_overflowCheck : Types.ty -> exp * exp -> exp
  val Int_mul_overflowCheck : Types.ty -> exp * exp -> exp
  val Int_sub_overflowCheck : Types.ty -> exp * exp -> exp
  val Int_toInt_unsafe : Types.ty * Types.ty -> exp -> exp
  val Word_lt : Types.ty -> exp * exp -> exp
  val Word_gt : Types.ty -> exp * exp -> exp
  val Word_lteq : Types.ty -> exp * exp -> exp
  val Word_gteq : Types.ty -> exp * exp -> exp
  val Word_arshift_unsafe : Types.ty -> exp * exp -> exp
  val Word_lshift_unsafe : Types.ty -> exp * exp -> exp
  val Word_rshift_unsafe : Types.ty -> exp * exp -> exp
  val Word_toWord : Types.ty * Types.ty -> exp -> exp
  val Word_add : Types.ty -> exp * exp -> exp
  val Word_sub : Types.ty -> exp * exp -> exp
  val Word_andb : Types.ty -> exp * exp -> exp
  val Word_orb : Types.ty -> exp * exp -> exp
  val Word_xorb : Types.ty -> exp * exp -> exp
  val Word_fromInt : Types.ty * Types.ty -> exp -> exp
  val Word_toInt : Types.ty * Types.ty -> exp -> exp
  val Word_toIntX_unsafe : Types.ty * Types.ty -> exp -> exp
  val Word_div_unsafe : Types.ty -> exp * exp -> exp
  val Word_mod_unsafe : Types.ty -> exp * exp -> exp
  val Real_isNan : Types.ty -> exp -> exp
  val Real_equal : Types.ty -> exp * exp -> exp
  val Real_gteq : Types.ty -> exp * exp -> exp
  val Real_lteq : Types.ty -> exp * exp -> exp
  val Real_sub : Types.ty -> exp * exp -> exp
  val allocExnTag : {builtin:bool, path:Symbol.longsymbol, ty:Types.ty} -> exp
  val extractExnTag : exp -> exp
  val extractExnArg : exp * Types.ty -> exp
  val composeExn : exp * Loc.loc * exp option -> exp
  val emit : TypedLambda.loc -> exp -> TypedLambda.tlexp

end
